﻿<h1>Go细节101</h1>

<div>
索引：

<ul class="summaries" id="details.html">
<li>
	代码包相关的细节：
	<ul class="index">
	<li>
		<a class="index" href="#import-package-multiple-times">一个包可以在一个源文件里被引入多次。</a>
	</li>
	<li>
		<a class="index" href="#force-import-path">在<code>package mypkg</code>之后的注释<code>// import "x.y.z/mypkg"</code>对标准Go编译器是有意义的。</a>
	</li>
	</ul>
</li>
<li>
	控制流相关的细节：
	<ul class="index">
	<li>
		<a class="index" href="#default-branch-position">在<code>switch</code>和<code>select</code>流程控制代码块中，<code>default</code>分支可以放在所有的<code>case</code>分支之前或者所有的<code>case</code>分支之后，也可以放在<code>case</code>分支之间。</a>
	</li>
	<li>
		<a class="index" href="#constant-case-expressions"><code>switch</code>流程控制代码块中的数字常量case表达式不能重复，但是布尔常量case表达式可以重复。</a>
	</li>
	<li>
		<a class="index" href="#switch-expressions-are-typed"><code>switch</code>流程控制代码块里的switch表达式总是被估值为类型确定值。</a>
	</li>
	<li>
		<a class="index" href="#default-switch-expression-value"><code>switch</code>流程控制代码块中的switch表达式的缺省默认值为类型确定值<code>true</code>（其类型为预定义类型<code>bool</code>）。</a>
	</li>
	<li>
		<a class="index" href="#open-brace-on-the-next-line">有时候，显式代码块的开括号<code>{</code>可以放在下一行。</a>
	</li>
	<li>
		<a class="index" href="#some-case-branch-blocks-must-be-explicit">有些<code>case</code>分支代码块必须是显式的。</a>
	</li>
	<li>
		<a class="index" href="#defer-modify-results">嵌套的延迟函数调用可以修改外层函数的返回结果。</a>
	</li>
	<li>
		<a class="index" href="#no-op-recover-calls">某些<code>recover</code>函数调用是空操作。</a>
	</li>
	<li>
		<a class="index" href="#os-exit-runtime-goexit">我们可以使用<code>os.Exit</code>函数调用退出一个程序和使用<code>runtime.Goexit</code>函数调用退出一个协程。</a>
	</li>
	</ul>
</li>
<li>
	操作符相关的细节：
	<ul class="index">
	<li>
		<a class="index" href="#some-operator-precedence">递增运算符<code>++</code>和递减运算符<code>--</code>的优先级低于解引用运算符<code>*</code>和取地址运算符<code>&amp;</code>，解引用运算符和取地址运算符的优先级低于选择器<code>.</code>中的属性选择操作符。</a>
	</li>
	<li>
		<a class="index" href="#type-deduction-in-bit-shift">移位运算中的左类型不确定操作数的类型推断规则取决于右操作数是否是常量。</a>
	</li>
	</ul>
</li>
<li>
	指针相关的细节：
	<ul class="index">
	<li>
		<a class="index" href="#conversion-of-pointers-with-different-underlying-types">如果两个指针的类型具有不同的底层类型但是它们的基类型却共享相同的底层类型，则这两个指针值可以间接相互转换为对方的类型。</a>
	</li>
	<li>
		<a class="index" href="#addresses-of-zeor-sized-values">两个零尺寸值的地址可能相等，也可能不相等。</a>
	</li>
	<li>
		<a class="index" href="#self-based-pointer-type">一个指针类型的基类型可以为此指针类型自身。</a>
	</li>
	<li>
		<a class="index" href="#pointer-selector-shorthands">有关选择器缩写形式的细节。</a>
	</li>
	</ul>
</li>
<li>
	容器相关的细节：
	<ul class="index">
	<li>
		<a class="index" href="#composite-literal-simplification">有时候，嵌套组合字面量可以被简化。</a>
	</li>
	<li>
		<a class="index" href="#use-pointer-as-array">在某些情形下，我们可以将数组指针当作数组来用。</a>
	</li>
	<li>
		<a class="index" href="#nil-map-element-retrieving">从nil映射中读取元素不会导致崩溃，读取结果是一个零元素值。</a>
	</li>
	<li>
		<a class="index" href="#nil-map-element--deletion">从一个nil映射中删除一个条目不会导致崩溃，这是一个空操作。</a>
	</li>
	<li>
		<a class="index" href="#append-slice-elements"><code>append</code>函数调用的结果可能会与原始切片共享一些元素，也可能不共享任何元素。</a>
	</li>
	<li>
		<a class="index" href="#subslice">从一个基础切片派生出的子切片的长度可能大于基础切片的长度。</a>
	</li>
	<li>
		<a class="index" href="#derive-from-nil-slice">从一个nil切片中派生子切片是允许的，只要子切片表达式中使用的所有索引都为零，则不会有恐慌产生，结果子切片同样是一个nil切片。</a>
	</li>
	<li>
		<a class="index" href="#range-over-nil-map-and-slice">用<code>range</code>遍历nil映射或者nil切片是没问题的，这属于空操作。</a>
	</li>
	<li>
		<a class="index" href="#range-over-nil-array-pointer">用<code>range</code>遍历nil数组指针时，如果忽略或省略第二个迭代变量，则此遍历是没问题的。遍历中的循环步数为相应数组类型的长度。</a>
	</li>
	<li>
		<a class="index" href="#modify-slice-length-and-capacity-separately">切片的长度和容量可以被单独修改。</a>
	</li>
	<li>
		<a class="index" href="#indexes-in-composite-literals">切片和数组组合字面量中的索引必须是非负常量。</a>
	</li>
	<li>
		<a class="index" href="#constant-keys-in-composite-literals">切片/数组/映射组合字面量的常量索引和键值不能重复。</a>
	</li>
	<li>
		<a class="index" href="#array-slice-element-addressability">不可寻址的数组的元素依旧是不可寻址的，但是不可寻址的切片的元素总是可寻址的。</a>
	</li>
	<li>
		<a class="index" href="#array-slice-derivable">可以从不可寻址的切片派生子切片，但是不能从不可寻址的数组派生子切片。</a>
	</li>
	<li>
		<a class="index" href="#nan-as-map-keys">把以<code>NaN</code>做为键值的条目放如映射就宛如把条目放入黑洞一样。</a>
	</li>
	<li>
		<a class="index" href="#capacity-of-slice-from-string">字符串转换为byte切片或rune切片后的结果切片的容量可能会大于长度。</a>
	</li>
	<li>
		<a class="index" href="#different-loops">对于切片<code>s</code>，循环<code>for i = range s {...}</code>并不等价于循环<code>for i = 0; i &lt; len(s); i++ {...}</code>。</a>
	</li>
	</ul>
</li>
<li>
	函数和方法相关的细节：
	<ul class="index">
	<li>
		<a class="index" href="#call-as-expression">一个多返回值函数调用表达式不能和其它表达式混用在一个赋值语句的右侧或者另一个函数调用的实参列表中。</a>
	</li>
	<li>
		<a class="index" href="#compile-time-evaluated-calls">某些函数调用是在在编译时刻被估值的。</a>
	</li>
	<li>
		<a class="index" href="#method-as-function">每一个方法都对应着一个隐式声明的函数。</a>
	</li>
	</ul>
</li>
<li>
	接口相关的细节：
	<ul class="index">
	<li>
		<a class="index" href="#comparison-interfaces-may-panic">如果两个接口值具有相同的动态类型并且此动态类型不支持比较，则比较这两个接口值将导致一个恐慌。</a>
	</li>
	<li>
		<a class="index" href="#type-assertion-to-interface-type">类型断言可以用于将一个接口值转换为另一个接口类型，即使此接口值的类型并未实现另一个接口类型。</a>
	</li>
	<li>
		<a class="index" href="#failed-type-assertion-may-panic">一个失败的类型断言的可选的第二个结果是否被舍弃将影响此类型断言的行为。</a>
	</li>
	<li>
		<a class="index" href="#impossible-to-interface-assertion">关于在编译时刻即可确定总是失败的目标类型为接口类型的断言。</a>
	</li>
	<!--
	<li>
		<a class="index" href="#interface-comparison-complexity">对于标准编译器来说，比较两个接口值的时间复杂度可能是<code><i>O</i>(1)</code>，也可能是<code><i>O</i>(n)</code>。</a>
	</li>
	<li>
		<a class="index" href="#interface-copy-complexity">对于标准编译器来说，复制一个接口值的时间复杂度为<code><i>O</i>(1)</code>。</a>
	</li>
	-->
	<li>
		<a class="index" href="#errors-new-different-returns">以相同实参调用两次<code>errors.New</code>函数返回的两个<code>error</code>值是不相等的。</a>
	</li>
	</ul>
</li>
<li>
	管道相关的细节：
	<ul class="index">
	<li>
		<a class="index" href="#receive-only-channel-canot-be-closed">单向接收通道无法被关闭。</a>
	</li>
	<li>
		<a class="index" href="#send-to-closed-channel-is-non-blocking">发送一个值到一个已关闭的通道被视为一个非阻塞操作，该操作会导致恐慌。</a>
	</li>
	</ul>
</li>
<li>
	更多关于类型和值的细节：
	<ul class="index">
	<li>
		<a class="index" href="#local-type-declaration">类型可以在声明函数体内。</a>
	</li>
	<li>
		<a class="index" href="#final-zero-size-field">对于标准编译器，结构体中的某些零尺寸字段的尺寸有可能会被视为一个字节。</a>
	</li>
	<li>
		<a class="index" href="#nan-inf">NaN != NaN，Inf == Inf。</a>
	</li>
	<li>
		<a class="index" href="#non-exported-names-from-different-packages">不同代码包中的两个非导出方法名和结构体字段名总是被视为不同的名称。</a>
	</li>
	<!--li>
		<a class="index" href="#compare-values-with-both-comparable-and-incomparable-parts">比较同时含有可比较和不可比较字段的结构体值或者同时含有可比较和不可比较字段的数组值的行为是未定义的。</a>

	</li-->
	<li>
		<a class="index" href="#blank-fields-are-ignored-in-comparisons">在结构体值的比较中，名为空标识符的字段将被忽略。</a>
	</li>
	</ul>
</li>
<li>
	杂项：
	<ul class="index">
	<li>
		<a class="index" href="#sometimes-parentheses-are-required">在某些很少见的场景中，圆括号是必需的。</a>
	</li>
	<!--
	<li>
		<a class="index" href="#main-entry-function-absence">一个程序可能并不需要一个<code>main</code>入口函数即可运行。</a>
	</li>
	-->
	<li>
		<a class="index" href="#stack-overflow-is-unrecoverable">栈溢出不可被挽救，它将使程序崩溃。</a>
	</li>
	<li>
		<a class="index" href="#some-evaluation-order-are-compiler-dependent">某些表达式的估值顺序取决于具体编译器实现。</a>
	</li>

	</ul>
</li>
<li>
	标准包相关的细节：
	<ul class="index">
	<li>
		<a class="index" href="#reflect-deep-equal"><code>reflect.DeepEqual(x, y)</code>和<code>x == y</code>的结果可能会不同。</a>
	</li>
	<li>
		<a class="index" href="#reflect-value-bytes"><code>reflect.Value.Bytes()</code>方法返回一个<code>[]byte</code>值，它的元素类型<code>byte</code>可能并非属主参数代表的Go切片值的元素类型。</a>
	</li>
	<li>
		<a class="index" href="#check-file-existent">我们应该使用<code>os.IsNotExist(err)</code>而不是<code>err == os.ErrNotExist</code>来检查文件是否存在。</a>
	</li>
	<li>
		<a class="index" href="#boolean-flag"><code>flag</code>标准库包对待布尔选项不同于整数和字符串选项。</a>
	</li>
	<li>
		<a class="index" href="#printf-positional-arguments"><code>[Sp|Fp|P]rintf</code>支持位置参数。</a>
	</li>
	</ul>
</li>
</ul>
</div>

<div class="summaries-items">

<a class="anchor" id="import-package-multiple-times"></a>
<h3>一个包可以在一个源文件里被引入多次。</h3>

<div>
<p>
一个Go源文件可以多次引入同一个包。但是每次的引入名称必须不同。这些相同的包引入引用着同一个包实例。
</p>

示例：
<pre class="line-numbers"><code class="language-go">package main

import "fmt"
import "io"
import inout "io"

func main() {
	fmt.Println(&inout.EOF == &io.EOF) // true
}
</code></pre>
</div>

<a class="anchor" id="force-import-path"></a>
<h3>在<code>package mypkg</code>之后的注释<code>// import "x.y.z/mypkg"</code>对标准Go编译器是有意义的。</h3>

<div>
例如，当标准编译器编译导入此包的源文件时，以下包的导入路径必须是 <code>"x.y.z/mypkg"</code>。

<pre class="line-numbers"><code class="language-go">package mypkg // import "x.y.z/mypkg"
...
</code></pre>

<p>
但是，从Go官方工具链1.11开始，此约束<a href="https://golang.org/cmd/go/#hdr-Import_path_checking">对于支持模块（modules）或者处于项目vendor目录下的库包不起作用</a>。
</p>
</div>

<a class="anchor" id="default-branch-position"></a>
<h3>在<code>switch</code>和<code>select</code>流程控制代码块中，<code>default</code>分支可以放在所有的<code>case</code>分支之前或者所有的<code>case</code>分支之后，也可以放在<code>case</code>分支之间。</h3>

<div>
示例：

<pre class="line-numbers"><code class="language-go">	switch n := rand.Intn(3); n {
	case 0: fmt.Println("n == 0")
	case 1: fmt.Println("n == 1")
	default: fmt.Println("n == 2")
	}

	switch n := rand.Intn(3); n {
	default: fmt.Println("n == 2")
	case 0: fmt.Println("n == 0")
	case 1: fmt.Println("n == 1")
	}

	switch n := rand.Intn(3); n {
	case 0: fmt.Println("n == 0")
	default: fmt.Println("n == 2")
	case 1: fmt.Println("n == 1")
	}

	var x, y chan int

	select {
	case <-x:
	case y <- 1:
	default:
	}

	select {
	case <-x:
	default:
	case y <- 1:
	}

	select {
	default:
	case <-x:
	case y <- 1:
	}
</code></pre>

<p>
</p>

</div>

<a class="anchor" id="constant-case-expressions"></a>
<h3><code>switch</code>流程控制代码块中的数字常量case表达式不能重复，但是布尔常量case表达式可以重复。</h3>

<div>
例如，下面的代码在编译时会失败。

<pre class="line-numbers"><code class="language-go">package main

func main() {
	switch 123 {
	case 123:
	case 123: // error: duplicate case
	}
}
</code></pre>

但是下面的代码在编译时是没问题的。

<pre class="line-numbers"><code class="language-go">package main

func main() {
	switch false {
	case false:
	case false:
	}
}
</code></pre>

<p>
关于原因，请阅读<a href="https://github.com/golang/go/issues/28357">这个issue</a>。
此行为依赖于编译器。事实上，标准编译器同样不允许重复的字符串case表达式，但是gccgo编译器却允许。
</p>
</div>

<a class="anchor" id="switch-expressions-are-typed"></a>
<h3><code>switch</code>流程控制代码块里的switch表达式总是被估值为类型确定值。</h3>

<div>
例如，在下列<code>switch</code>代码块中的switch表达式<code>123</code>被视为一个<code>int</code>值，而不是一个类型不确定的整数。

<pre class="line-numbers"><code class="language-go">package main

func main() {
	switch 123 {
	case int64(123):  // error: 类型不匹配
	case uint32(789): // error: 类型不匹配
	}
}
</code></pre>

<p>
</p>
</div>

<a class="anchor" id="default-switch-expression-value"></a>
<h3><code>switch</code>流程控制代码块中的switch表达式的缺省默认值为类型确定值<code>true</code>（其类型为预定义类型<code>bool</code>）。</h3>

<div>
例如，下列程序会打印出<code>true</code>。

<pre class="line-numbers"><code class="language-go">package main

import "fmt"

func main() {
	switch { // <=> switch true {
	case true:  fmt.Println("true")
	case false: fmt.Println("false")
	}
}
</code></pre>

<p>
</p>
</div>

<a class="anchor" id="open-brace-on-the-next-line"></a>
<h3>有时候，显式代码块的开括号<code>{</code>可以放在下一行。</h3>

<div>
例如：

<pre class="line-numbers"><code class="language-go">package main

func main() {
	var i = 0
Outer:
	for
	{ // 在这里断行是没问题的
		switch
		{ // 在这里断行是没问题的
		case i == 5:
			break Outer
		default:
			i++
		}
	}
}
</code></pre>

<p></p>

下面程序的结果会打印什么？<code>true</code>还是<code>false</code>？
答案是<code>true</code>。
关于原因请阅读<a href="line-break-rules.html">Go中的代码断行规则</a>一文。

<pre class="line-numbers"><code class="language-go">package main

import "fmt"

func False() bool {
	return false
}

func main() {
	switch False()
	{
	case true:  fmt.Println("true")
	case false: fmt.Println("false")
	}
}
</code></pre>

<p>
</p>

</div>

<a class="anchor" id="some-case-branch-blocks-must-be-explicit"></a>
<h3>有些<code>case</code>分支代码块必须是显式的。</h3>

<div>
例如，下面的程序会在编译时将失败。

<pre class="line-numbers"><code class="language-go">func demo(n, m int) (r int) {
	switch n {
	case 123:
		if m > 0 {
			goto End
		}
		r++

		End: // syntax error: 标签后缺少语句
	default:
		r = 1
	}
	return
}
</code></pre>

为了编译通过，<code>case</code>分支代码块必须改成显式的：

<pre class="line-numbers"><code class="language-go">func demo(n, m int) (r int) {
	switch n {
	case 123: {
		if m > 0 {
			goto End
		}
		r++

		End:
	}
	default:
		r = 1
	}
	return
}
</code></pre>

另外，我们可以在标签<code>End:</code>之后加一个分号，如下所示：

<pre class="line-numbers"><code class="language-go">func demo(n, m int) (r int) {
	switch n {
	case 123:
		if m > 0 {
			goto End
		}
		r++

		End:;
	default:
		r = 1
	}
	return
}
</code></pre>

<p>
关于原因，请阅读<a href="line-break-rules.html">Go的代码断行规则</a>一文。
</p>

</div>

<a class="anchor" id="defer-modify-results"></a>
<h3>嵌套的延迟函数调用可以修改外层函数的返回结果。</h3>

<div>
例如：

<pre class="line-numbers"><code class="language-go">package main

import "fmt"

func F() (r int) {
	defer func() {
		r = 789
	}()

	return 123 // <=> r = 123; return
}

func main() {
	fmt.Println(F()) // 789
}
</code></pre>

<p>
</p>
</div>

<a class="anchor" id="no-op-recover-calls"></a>
<h3>某些<code>recover</code>函数调用是空操作。</h3>

<p>
我们需要在正确的地方调用<code>recover</code>函数。
关于细节，请阅读 <a href="panic-and-recover-more.html">在正确的位置调用内置函数<code>recover</code></a>一文。
</p>

<a class="anchor" id="os-exit-runtime-goexit"></a>
<h3>我们可以使用<code>os.Exit</code>函数调用退出一个程序和使用<code>runtime.Goexit</code>函数调用退出一个协程。</h3>

<!--
https://github.com/golang/go/issues/29226 a bug of goexit
-->

<div>
<p>
我们可以通过调用<code>os.Exit</code>函数从任何函数里退出一个程序。
<code>os.Exit</code>函数调用接受一个<code>int</code>代码值做为参数并将此代码返回给操作系统。
</p>

示例：

<pre class="line-numbers"><code class="language-go">// exit-example.go
package main

import "os"
import "time"

func main() {
	go func() {
		time.Sleep(time.Second)
		os.Exit(1)
	}()
	select{}
}
</code></pre>

运行：

<pre class="output"><code>$ go run a.go
exit status 1
$ echo $?
1
</code></pre>

<p>
</p>

<p>
我们可以通过调用<code>runtime.Goexit</code>函数退出一个goroutine。
<code>runtime.Goexit</code>函数没有参数。
</p>

在下面的示例中，文字<code>Java</code>将不会被打印出来。

<pre class="line-numbers"><code class="language-go">package main

import "fmt"
import "runtime"

func main() {
	c := make(chan int)
	go func() {
		defer func() {c <- 1}()
		defer fmt.Println("Go")
		func() {
			defer fmt.Println("C")
			runtime.Goexit()
		}()
		fmt.Println("Java")
	}()
	<-c
}
</code></pre>

<p>
</p>

</div>

<a class="anchor" id="some-operator-precedence"></a>
<h3>递增运算符<code>++</code>和递减运算符<code>--</code>的优先级低于解引用运算符<code>*</code>和取地址运算符<code>&amp;</code>，解引用运算符和取地址运算符的优先级低于选择器<code>.</code>中的属性选择操作符。</h3>

<div>
例如：

<pre class="line-numbers"><code class="language-go">package main

import "fmt"

type T struct {
	x int
	y *int
}

func main() {
	var t T
	p := &t.x // <=> p := &(t.x)
	fmt.Printf("%T\n", p) // *int

	*p++ // <=> (*p)++
	*p-- // <=> (*p)--

	t.y = p
	a := *t.y // <=> *(t.y)
	fmt.Printf("%T\n", a) // int
}
</code></pre>

<p>
</p>
</div>

<a class="anchor" id="type-deduction-in-bit-shift"></a>
<h3>移位运算中的左类型不确定操作数的类型推断规则取决于右操作数是否是常量。</h3>

<div>


<pre class="line-numbers"><code class="language-go">package main

func main() {
}

const M  = 2
var _ = 1.0 << M // 编译没问题。1.0将被推断为一个int值。

var N = 2
var _ = 1.0 << N // 编译失败。1.0将被推断为一个float64值。
</code></pre>

<p>
关于原因请阅读<a href="operators.html#bitwise-shift-left-operand-type-deduction">运算操作符</a>一文。
</p>
</div>

<a class="anchor" id="conversion-of-pointers-with-different-underlying-types"></a>
<h3>如果两个指针的类型具有不同的底层类型但是它们的基类型却共享相同的底层类型，则这两个指针值可以间接相互转换为对方的类型。</h3>

<div>

例如：

<pre class="line-numbers"><code class="language-go">package main

type MyInt int64
type Ta    *int64
type Tb    *MyInt

func main() {
	var a Ta
	var b Tb

	//a = Ta(b) // error: 直接转换是不允许的。

	// 但是间接转换是允许的。
	y := (*MyInt)(b)
	x := (*int64)(y)
	a = x           // 等价于下一行
	a = (*int64)(y) // 等价于下一行
	a = (*int64)((*MyInt)(b))
	_ = a
}
</code></pre>

<p>
</p>
</div>

<a class="anchor" id="addresses-of-zeor-sized-values"></a>
<h3>两个零尺寸值的地址可能相等，也可能不相等。</h3>
<!--
https://github.com/golang/go/issues/12726
-->

<div>
两个零尺寸值的地址是否相等时依赖于具体编译器实现以及具体编译器版本。

<pre class="line-numbers"><code class="language-go">package main

import "fmt"

func main() {
	a := struct{}{}
	b := struct{}{}
	x := struct{}{}
	y := struct{}{}
	m := [10]struct{}{}
	n := [10]struct{}{}
	o := [10]struct{}{}
	p := [10]struct{}{}

	fmt.Println(&x, &y, &o, &p)

	// 对于标准编译器1.15版本，x、y、o和p将
	// 逃逸到堆上，但是a、b、m和n则开辟在栈上。

	fmt.Println(&a == &b) // false
	fmt.Println(&x == &y) // true
	fmt.Println(&a == &x) // false

	fmt.Println(&m == &n) // false
	fmt.Println(&o == &p) // true
	fmt.Println(&n == &p) // false
}
</code></pre>

<p>
上面代码中所示的输出是针对标准编译器1.15版本的。
</p>
</div>

<a class="anchor" id="self-based-pointer-type"></a>
<h3>一个指针类型的基类型可以为此指针类型自身。</h3>

<div>

例如：

<pre class="line-numbers"><code class="language-go">package main

func main() {
	type P *P
	var p P
	p = &p
	p = **************p
}
</code></pre>

<p>
</p>

类似的，
<ul>
<li>
	一个切片类型的元素类型可以是此切片类型自身，
</li>
<li>
	一个映射类型的元素类型可以是此映射类型自身，
</li>
<li>
	一个通道类型的元素类型可以是此通道类型自身，
</li>
<li>
	一个函数类型的输入参数和返回结果值类型可以是此函数类型自身。
</li>
</ul>

<pre class="line-numbers"><code class="language-go">package main

func main() {
	type S []S
	type M map[string]M
	type C chan C
	type F func(F) F

	s := S{0:nil}
	s[0] = s
	m := M{"Go": nil}
	m["Go"] = m
	c := make(C, 3)
	c <- c; c <- c; c <- c
	var f F
	f = func(F)F {return f}

	_ = s[0][0][0][0][0][0][0][0]
	_ = m["Go"]["Go"]["Go"]["Go"]
	<-<-<-c
	f(f(f(f(f))))
}
</code></pre>

<p>
</p>

</div>

<a class="anchor" id="pointer-selector-shorthands"></a>
<h3>有关选择器缩写形式的细节。</h3>

<div>

<p>
无论一个指针值的类型是定义的还是非定义的，如果它的（指针）类型的基类型为一个结构体类型，则我们可以使用此指针值来选择它所引用着的结构体中的字段。
但是，如果此指针的类型为一个定义的类型，则我们不能使用此指针值来选择它所引用着的结构体中的方法。
</p>

<p>
我们总是不能使用二级以上指针来选择结构体字段和方法。
</p>

<pre class="line-numbers"><code class="language-go">package main

type T struct {
	x int
}
func (T) m(){} // T有一个方法m。

type P *T  // P为一个定义的一级指针。
type PP *P // PP为一个定义的二级指针。

func main() {
	var t T
	var tp = &t
	var tpp = &tp
	var p P = tp
	var pp PP = &p
	tp.x = 12  // 没问题
	p.x = 34   // 没问题
	pp.x = 56  // error: 类型PP没有名为x的字段或者方法。
	tpp.x = 78 // error: 类型**T没有名为x的字段或者方法。

	tp.m()  // 没问题，因为类型*T也有一个m方法。
	p.m()   // error: 类型P没有名为m的字段或者方法。
	pp.m()  // error: 类型PP没有名为m的字段或者方法。
	tpp.m() // error: 类型**T没有名为m的字段或者方法。
}
</code></pre>
<p>
</p>
</div>

<a class="anchor" id="composite-literal-simplification"></a>
<h3>有时候，嵌套组合字面量可以被简化。</h3>

<p>
关于细节，请阅读<a href="container.html#composite-literal-simplification">内嵌组合字面量可以被简化</a>这一章节。
</p>

<a class="anchor" id="use-pointer-as-array"></a>
<h3>在某些情形下，我们可以将数组指针当作数组来用。</h3>

<p>
关于细节，请阅读<a href="container.html#use-pointer-as-array">把数组指针当做数组来使用</a>这一章节。
</p>

<a class="anchor" id="nil-map-element-retrieving"></a>
<h3>从nil映射中读取元素不会导致崩溃，读取结果是一个零元素值。</h3>

<div>

例如，函数<code>Foo1</code>和<code>Foo2</code>是等价的，但是函数<code>Foo2</code>比函数<code>Foo1</code>简洁得多。

<pre class="line-numbers"><code class="language-go">func Foo1(m map[string]int) int {
	if m != nil {
		return m["foo"]
	}
	return 0
}

func Foo2(m map[string]int) int {
	return m["foo"]
}
</code></pre>

<p>
</p>
</div>

<a class="anchor" id="nil-map-element--deletion"></a>
<h3>从一个nil映射中删除一个条目不会导致崩溃，这是一个空操作。</h3>

<div>

例如，下面这个程序不会因为恐慌而崩溃。

<pre class="line-numbers"><code class="language-go">package main

func main() {
	var m map[string]int // nil
	delete(m, "foo")
}
</code></pre>

<p>
</p>
</div>

<a class="anchor" id="append-slice-elements"></a>
<h3><code>append</code>函数调用的结果可能会与原始切片共享一些元素，也可能不共享任何元素。</h3>

<p>
关于细节，请阅读<a href="container.html#element-addition-deletion">添加和删除容器元素</a>这一章节。
</p>

<a class="anchor" id="subslice"></a>
<h3>从一个基础切片派生出的子切片的长度可能大于基础切片的长度。</h3>

<div>

例如：

<pre class="line-numbers"><code class="language-go">package main

import "fmt"

func main() {
	s := make([]int, 3, 9)
	fmt.Println(len(s)) // 3
	s2 := s[2:7]
	fmt.Println(len(s2)) // 5
}
</code></pre>

<p>
关于细节，请阅读<a href="container.html#subslice">从数组或者切片派生切片</a>这一章节。
</p>
</div>

<a class="anchor" id="derive-from-nil-slice"></a>
<h3>从一个nil切片中派生子切片是允许的，只要子切片表达式中使用的所有索引都为零，则不会有恐慌产生，结果子切片同样是一个nil切片。</h3>

<div>

例如，下面的程序在运行时刻不会产生恐慌。

<pre class="line-numbers"><code class="language-go">package main

import "fmt"

func main() {
	var x []int // nil
	a := x[:]
	b := x[0:0]
	c := x[:0:0]
	// 下一行将打印出三个true。
	fmt.Println(a == nil, b == nil, c == nil)
}
</code></pre>

<p>
关于细节，请阅读<a href="container.html#subslice">从数组或者切片派生切片</a>这一章节。
</p>
</div>

<a class="anchor" id="range-over-nil-map-and-slice"></a>
<h3>用<code>range</code>遍历nil映射或者nil切片是没问题的，这属于空操作。</h3>

<div>

例如，下面的程序可以编译是没问题的。

<pre class="line-numbers"><code class="language-go">package main

func main() {
	var s []int // nil
	for range s {
	}

	var m map[string]int // nil
	for range m {
	}
}
</code></pre>

<p>
</p>
</div>

<a class="anchor" id="range-over-nil-array-pointer"></a>
<h3>用<code>range</code>遍历nil数组指针时，如果忽略或省略第二个迭代变量，则此遍历是没问题的。遍历中的循环步数为相应数组类型的长度。</h3>

<div>

例如，下面的程序会输出<code>01234</code>。

<pre class="line-numbers"><code class="language-go">package main

import "fmt"

func main() {
	var a *[5]int // nil
	for i, _ := range a {
		fmt.Print(i)
	}
}
</code></pre>

<p>
</p>
</div>

<a class="anchor" id="modify-slice-length-and-capacity-separately"></a>
<h3>切片的长度和容量可以被单独修改。</h3>

<p>
我们可以通过反射途径单独修改一个切片的长度或者容量。
关于细节，请阅读<a href="container.html#modify-slice-length-and-capacity">单独修改一个切片的长度或者容量</a>这一章节。
</p>

<a class="anchor" id="indexes-in-composite-literals"></a>
<h3>切片和数组组合字面量中的索引必须是非负常量。</h3>

<div>
例如，下面的程序将编译失败。

<pre class="line-numbers"><code class="language-go">var k = 1
var x = [2]int{k: 1} // error: 索引必须为一个常量
var y = []int{k: 1}  // error: 索引必须为一个常量
</code></pre>

<p>
注意，映射组合字面量中的键值不必为常量。
</p>
</div>

<a class="anchor" id="constant-keys-in-composite-literals"></a>
<h3>切片/数组/映射组合字面量的常量索引和键值不能重复。</h3>

<div>
例如，下面的程序将编译失败。

<pre class="line-numbers"><code class="language-go">// error: 重复的索引：1
var a = []bool{0: false, 1: true, 1: true}
// error: 重复的索引：0
var b = [...]string{0: "foo", 1: "bar", 0: "foo"}
// error: 重复的键值："foo"
var c = map[string]int{"foo": 1, "foo": 2}
</code></pre>

<p>
这个特性可以用于<a href="tips.html#assert-at-compile-time">在编译时刻断言某些条件</a>。
</p>
</div>

<a class="anchor" id="array-slice-element-addressability"></a>
<h3>不可寻址的数组的元素依旧是不可寻址的，但是不可寻址的切片的元素总是可寻址的。</h3>

<div>
<p>
原因是一个数组值的元素和此数组存储在同一个内存块中。
但是<a href="unofficial-faq.html#slice-elements-always-addressable">切片的情况大不相同</a>。
</p>

一个例子：

<pre class="line-numbers"><code class="language-go">package main

func main() {
	// 组合字面量是不可寻址的。

	/* 取容器元素的地址。 */

	// 取不可寻址的切片的元素的地址是没问题的
	_ = &[]int{1}[0]
	// error: 不能取不可寻址的数组的元素的地址
	_ = &[5]int{}[0]

	/* 修改元素值。 */

	// 修改不可寻址的切片的元素是没问题的
	[]int{1,2,3}[1] = 9
	// error: 不能修改不可寻址的数组的元素
	[3]int{1,2,3}[1] = 9
}
</code></pre>

<p>
</p>
</div>

<a class="anchor" id="array-slice-derivable"></a>
<h3>
可以从不可寻址的切片派生子切片，但是不能从不可寻址的数组派生子切片。
</h3>

<div>
<p>
原因和上一个细节是一样的。
</p>

例如：
<pre class="line-numbers"><code class="language-go">package main

func main() {
	// 映射元素是不可寻址的。

	// 下面几行编译没问题。
	_ = []int{6, 7, 8, 9}[1:3]
	var ms = map[string][]int{"abc": {0, 1, 2, 3}}
	_ = ms["abc"][1:3]

	// 下面几行将编译失败，因为不可从不可寻址的数组派生切片。
	/*
	_ = [...]int{6, 7, 8, 9}[1:3] // error
	var ma = map[string][4]int{"abc": {0, 1, 2, 3}}
	_ = ma["abc"][1:3]  // error
	*/
}
</code></pre>
<p>
</p>
</div>

<a class="anchor" id="nan-as-map-keys"></a>
<h3>把以<code>NaN</code>做为键值的条目放如映射就宛如把条目放入黑洞一样。</h3>

<div>
原因是<a href="#nan-inf">下面的另一个细节</a>中提到的<code>NaN != NaN</code>。
但是，在Go1.12之前，以<code>NaN</code>作为键值的元素只能在<code>for-range</code>循环中被找到；
从Go1.12开始，以<code>NaN</code>作为键值的元素也可以通过类似<code>fmt.Print</code>的函数打印出来。

<pre class="line-numbers"><code class="language-go">package main

import "fmt"
import "math"

func main() {
	var a = math.NaN()
	fmt.Println(a) // NaN

	var m = map[float64]int{}
	m[a] = 123
	v, present := m[a]
	fmt.Println(v, present) // 0 false
	m[a] = 789
	v, present = m[a]
	fmt.Println(v, present) // 0 false

	fmt.Println(m) // map[NaN:789 NaN:123]
	delete(m, a)   // no-op
	fmt.Println(m) // map[NaN:789 NaN:123]

	for k, v := range m {
		fmt.Println(k, v)
	}
	// the above loop outputs:
	// NaN 123
	// NaN 789
}
</code></pre>
<p>
注意：在Go1.12之前，两个<code>fmt.Println(m)</code>调用均打印出<code>map[NaN:&lt;nil&gt; NaN:&lt;nil&gt;]</code>。
</p>
</div>

<a class="anchor" id="capacity-of-slice-from-string"></a>
<h3>字符串转换为byte切片或rune切片后的结果切片的容量可能会大于长度。</h3>

<div>
<p>
我们不应该假设结果切片的长度和容量总是相等的。
</p>

在下面的例子中，如果最后一个<code>fmt.Println</code>行被删除，在其前面的两行会打印相同的值<code>32</code>，否则，一个打印<code>32</code>，一个打印<code>8</code>（对于标准编译器1.15版本来说）。

<pre class="line-numbers"><code class="language-go">package main

import "fmt"

func main() {
	s := "a"
	x := []byte(s)              // len(s) == 1
	fmt.Println(cap([]byte(s))) // 32
	fmt.Println(cap(x))         // 8
	fmt.Println(x)
}
</code></pre>

<p>
如果我们假设结果切片的长度和容量总是相等，<a href="https://github.com/go101/go101/wiki/The-capacity-of-the-result-byte-%28or-rune%29-slice-of-a-conversion-from-a-string-is-undefined">就可能写出一些有bug的代码</a>。
</p>
</div>

<a class="anchor" id="different-loops"></a>
<h3>对于切片<code>s</code>，循环<code>for i = range s {...}</code>并不等价于循环<code>for i = 0; i &lt; len(s); i++ {...}</code>。</h3>

<div>
对于这两个循环，迭代变量<code>i</code>的最终值可能是不同的。

<pre class="line-numbers"><code class="language-go">package main

import "fmt"

var i int

func fa(s []int, n int) int {
	i = n
	for i = 0; i < len(s); i++ {}
	return i
}

func fb(s []int, n int) int {
	i = n
	for i = range s {}
	return i
}

func main() {
	s := []int{2, 3, 5, 7, 11, 13}
	fmt.Println(fa(s, -1), fb(s, -1)) // 6 5
	s = nil
	fmt.Println(fa(s, -1), fb(s, -1)) // 0 -1
}
</code></pre>

<p>
</p>
</div>

<a class="anchor" id="call-as-expression"></a>
<h3>一个多返回值函数调用表达式不能和其它表达式混用在一个赋值语句的右侧或者另一个函数调用的实参列表中。</h3>

<p>
关于细节，请阅读<a href="function.html#call-as-expression">有返回值的函数的调用是一种表达式</a>这一章节。
</p>

<a class="anchor" id="compile-time-evaluated-calls"></a>
<h3>某些函数调用是在在编译时刻被估值的。</h3>

<p>
关于细节，请阅读<a href="summaries.html#compile-time-evaluation">哪些函数调用将在编译时刻被估值？</a>这一总结。
</p>

<a class="anchor" id="method-as-function"></a>
<h3>每一个方法都对应着一个隐式声明的函数。</h3>

<p>
关于细节，请阅读<a href="method.html#method-as-function">每个方法对应着一个隐式声明的函数</a>这一章节。
</p>

<a class="anchor" id="comparison-interfaces-may-panic"></a>
<h3>如果两个接口值具有相同的动态类型并且此动态类型不支持比较，则比较这两个接口值将导致一个恐慌。</h3>

<div>
例如：

<pre class="line-numbers"><code class="language-go">package main

func main() {
	var x interface{} = []int{}
	_ = x == x // panic
}
</code></pre>

<p>
</p>
</div>

<a class="anchor" id="type-assertion-to-interface-type"></a>
<h3>类型断言可以用于将一个接口值转换为另一个接口类型，即使此接口值的类型并未实现另一个接口类型。</h3>

<div>
例如：

<pre class="line-numbers"><code class="language-go">package main

type Foo interface {
	foo()
}

type T int
func (T) foo() {}

func main() {
	var x interface{} = T(123)
	// 下面这两行将编译失败。
	/*
	var _ Foo = x   // error: interface{}类型没有实现Foo类型
	var _ = Foo(x)  // error: interface{}类型没有实现Foo类型
	*/
	// 但是下面这行可以编译通过。
	var _ = x.(Foo) // okay
}
</code></pre>

<p>
</p>
</div>

<a class="anchor" id="failed-type-assertion-may-panic"></a>
<h3>一个失败的类型断言的可选的第二个结果是否被舍弃将影响此类型断言的行为。</h3>

<div>
如果第二个可选结果出现在失败的类型断言中，那么此类型断言不会导致恐慌。否则，恐慌将产生。
例如：

<pre class="line-numbers"><code class="language-go">package main

func main() {
	var x interface{} = true
	_, _ = x.(int) // 断言失败，但不会导致恐慌。
	_ = x.(int)    // 断言失败，并导致一个恐慌。
}
</code></pre>

<p>
</p>
</div>

<a class="anchor" id="impossible-to-interface-assertion"></a>
<h3>关于在编译时刻即可确定总是失败的目标类型为接口类型的断言。</h3>

<div>
在编译时刻，编译可以发现某些目标类型为接口类型的断言是不可能成功的。比如下面这个程序中的断言：

<pre class="line-numbers"><code class="language-go">package main

type Ia interface {
	m()
}

type Ib interface {
	m() int
}

type T struct{}

func (T) m() {}

func main() {
	var x Ia = T{}
	_ = x.(Ib) // panic: main.T is not main.Ib
}
</code></pre>

<p>
这样的断言并不会导致编译失败（但编译后的程序将在运行时刻产生恐慌）。
从官方Go工具链1.15开始，<code>go vet</code>会对对这样的断言做出警告。
</p>

</div>



<!--
<a class="anchor" id="interface-comparison-complexity"></a>
<h3>对于标准编译器来说，比较两个接口值的时间复杂度可能是<code><i>O</i>(1)</code>，也可能是<code><i>O</i>(n)</code>。</h3>

<div>
The time complexity depends on whether or not the direct parts
of the two equal interfaces both reference the undrelying value.
Please read the article <a href="value-part.html#interface-structure">value parts</a> for detail.

<pre class="line-numbers"><code class="language-go">package main

import "fmt"
import "time"

func main() {
	bigarr := [1 << 20]int{}

	type I interface{}

	// i0, i1 and i2 are three equal interfaces.
	var i0 I = bigarr // the dynamic value of i0 is a copy of bigarr.
	var i1 I = bigarr // the dynamic value of i1 is also a copy of bigarr.
	                  // Note, the dynamic values of i0 and i1 are
	                  // two different copies of bigarr.
	var i2 I = i1 // i2 shares the same dynamic value copy with i1.

	startTime := time.Now()
	_ = i0 == i1
	duration := time.Since(startTime)
	fmt.Println("duration for (i0 == i1):", duration)

	startTime = time.Now()
	_ = i1 == i2
	duration = time.Since(startTime)
	fmt.Println("duration for (i1 == i2):", duration)
}
</code></pre>

The output:
<pre class="output"><code>duration for (i0 == i1): 1.381337ms
duration for (i1 == i2): 609ns
</code></pre>
<p>
1ms is 1000000ns!
</p>
</div>

<a class="anchor" id="interface-copy-complexity"></a>
<h3>对于标准编译器来说，复制一个接口值的时间复杂度为<code><i>O</i>(1)</code>。</h3>

<p>
The <a href="https://golang.org/doc/faq#pass_by_value">official Go FAQ</a>
says <b><i>copying an interface value makes a copy of the thing stored in the interface value.</i></b>.
The article <a href="interface.html#boxing">interfaces in Go</a> mentions that,
for the standard Go compiler, the time complexity of copying an interface value
is <code><i>O</i>(1)</code>.
But the sizes of different dynamic values stored in interface values may
be different, why isn't the complexity <code><i>O</i>(n)</code>?
</p>

<p>
The reason is the dynamic values of interface values are all inmutable,
so the standard Go compiler makes an optimization here.
As the article <a href="value-part.html#interface-structure">value parts</a>
has explained, an non-nil interface value has an underlying part and
the direct part of the interface value stores a pointer which
references the underlying part. When the interface value is copied,
only its direct part is copied. For the standard Go compiler,
the sizes of the direct parts of all interface values are the same.
</p>
-->

<a class="anchor" id="errors-new-different-returns"></a>
<h3>以相同实参调用两次<code>errors.New</code>函数返回的两个<code>error</code>值是不相等的。</h3>

<div>
原因是<code>errors.New</code>函数会复制输入的字符串实参至一个局部变量并取此局部变量的指针作为返回<code>error</code>值的动态值。
两次调用会产生两个不同的指针。

<pre class="line-numbers"><code class="language-go">package main

import "fmt"
import "errors"

func main() {
	notfound := "not found"
	a, b := errors.New(notfound), errors.New(notfound)
	fmt.Println(a == b) // false
}
</code></pre>

<p>
</p>
</div>

<a class="anchor" id="receive-only-channel-canot-be-closed"></a>
<h3>单向接收通道无法被关闭。</h3>

<div>
例如，下面的代码会在编译时候失败。

<pre class="line-numbers"><code class="language-go">package main

func main() {
}

func foo(c <-chan int) {
	close(c) // error: 不能关闭单向接收通道
}
</code></pre>

<p>
</p>
</div>

<a class="anchor" id="send-to-closed-channel-is-non-blocking"></a>
<h3>发送一个值到一个已关闭的通道被视为一个非阻塞操作，该操作会导致恐慌。</h3>

<div>
例如，在下面的程序里，如果第二个<code>case</code>分支会被选中，则在运行时刻将产生一个恐慌。

<pre class="line-numbers"><code class="language-go">package main

func main() {
	var c = make(chan bool)
	close(c)
	select {
	case <-c:
	case c <- true: // panic: 向已关闭的通道发送数据
	default:
	}
}
</code></pre>

<p>
</p>
</div>

<a class="anchor" id="local-type-declaration"></a>
<h3>类型可以在声明函数体内。</h3>

<div>
类型可以声明在函数体内。例如，

<pre class="line-numbers"><code class="language-go">package main

func main() {
	type T struct{}
	type S = []int
}
</code></pre>
<p>
</p>
</div>

<a class="anchor" id="final-zero-size-field"></a>
<h3>对于标准编译器，结构体中的某些零尺寸字段的尺寸有可能会被视为一个字节。</h3>

<p>
关于细节，请阅读<a href="unofficial-faq.html#final-zero-size-field">这个FAQ条目</a>。
</p>

<a class="anchor" id="nan-inf"></a>
<h3>NaN != NaN，Inf == Inf。</h3>

<div>
此规则遵循IEEE-754标准，并与大多数其它语言是一致的。

<pre class="line-numbers"><code class="language-go">package main

import "fmt"
import "math"

func main() {
	var a = math.Sqrt(-1.0)
	fmt.Println(a)      // NaN
	fmt.Println(a == a) // false

	var x = 0.0
	var y = 1.0 / x
	var z = 2.0 * y
	fmt.Println(y, z, y == z) // +Inf +Inf true
}
</code></pre>
<p>
</p>
</div>

<a class="anchor" id="non-exported-names-from-different-packages"></a>
<h3>不同代码包中的两个非导出方法名和结构体字段名总是被视为不同的名称。</h3>

<div>
例如，在包<code>foo</code>中声明了如下的类型：

<pre class="line-numbers"><code class="language-go">package foo

type I = interface {
	about() string
}

type S struct {
	a string
}

func (s S) about() string {
	return s.a
}
</code></pre>

在包<code>bar</code>中声明了如下的类型：

<pre class="line-numbers"><code class="language-go">package bar

type I = interface {
	about() string
}

type S struct {
	a string
}

func (s S) about() string {
	return s.a
}
</code></pre>

那么，
<ul>
<li>
	两个包中的两个类型<code>S</code>的值不能相互转换。
</li>
<li>
	两个包中的两个接口类型指定了两个不同的方法集。
</li>
<li>
	类型<code>foo.S</code>没有实现接口类型 <code>bar.I</code>。
</li>
<li>
	类型<code>bar.S</code>没有实现接口类型<code>foo.I</code>。
</li>
</ul>

<pre class="line-numbers"><code class="language-go">package main

import "包2/foo"
import "包2/bar"

func main() {
	var x foo.S
	var y bar.S
	var _ foo.I = x
	var _ bar.I = y

	// 下面这些行将编译失败。
	x = foo.S(y)
	y = bar.S(x)
	var _ foo.I = y
	var _ bar.I = x
}
</code></pre>

</div>

<!--
<a class="anchor" id="compare-values-with-both-comparable-and-incomparable-parts"></a>
<h3>比较同时含有可比较和不可比较字段的结构体值或者同时含有可比较和不可比较字段的数组值的行为是未定义的。</h3>

<div>
<p>
当然，这里提到的不可比较值必须呈现为接口值，否则，这样的比较是编译不通过的。
</p>

尽管看上去目前的官方标准编译器对结构值的比较是一个字段一个字段比较，对数组的比较是一个元素一个元素比较，直到一个不相等的情况发生或者一个恐慌产生，
但是这样的比较的行为目前（Go 1.15）确实是<a href="https://github.com/golang/go/issues/8606">未定义的</a>。

<pre class="line-numbers"><code class="language-go">package main

import "fmt"

func cmpS(a, b S) {
	defer func() {
		if recover() != nil {
			fmt.Println("panic")
		}
	}()
	fmt.Println(a == b)
}

func cmpA(x, y A) {
	defer func() {
		if recover() != nil {
			fmt.Println("panic")
		}
	}()
	fmt.Println(x == y)
}

type S struct{x, y interface{}}
type A [2]interface{}

func main() {
	var f func()
	cmpS(S{1, f}, S{2, f}) // false（panic也是可以的）
	cmpS(S{f, 1}, S{f, 2}) // panic（false也是可以的）
	cmpA(A{1, f}, A{2, f}) // false（panic也是可以的）
	cmpA(A{f, 1}, A{f, 2}) // panic（false也是可以的）
}
</code></pre>

<p>
</p>

</div>
-->

<a class="anchor" id="blank-fields-are-ignored-in-comparisons"></a>
<h3>在结构体值的比较中，名为空标识符的字段将被忽略。</h3>

<div>
比如，下面这个程序将打印出<code>true</code>。

<pre class="line-numbers"><code class="language-go">package main

import "fmt"

type T struct {
	_ int
	_ bool
}

func main() {
	var t1 = T{123, true}
	var t2 = T{789, false}
	fmt.Println(t1 == t2) // true
}
</code></pre>

<p>
</p>

</div>

<a class="anchor" id="sometimes-parentheses-are-required"></a>
<h3>在某些很少见的场景中，圆括号是必需的。</h3>

<div>
例如：

<pre class="line-numbers"><code class="language-go">package main

type T struct{x, y int}

func main() {
	// 因为{}的烦扰，下面这三行均编译失败。
	/*
	if T{} == T{123, 789} {}
	if T{} == (T{123, 789}) {}
	if (T{}) == T{123, 789} {}
	var _ = func()(nil) // nil被认为是一个类型
	*/

	// 必须加上一对小括号()才能编译通过。
	if (T{} == T{123, 789}) {}
	if (T{}) == (T{123, 789}) {}
	var _ = (func())(nil) // nil被认为是一个值
}
</code></pre>

<p>
</p>
</div>

<!--
<a class="anchor" id="main-entry-function-absence"></a>
<h3>一个程序可能并不需要一个<code>main</code>入口函数即可运行。</h3>

<div>
The following program <a href="https://github.com/golang/go/issues/21256">compiles okay before Go 1.11</a>,
for the standard Go compiler.
But since Go 1.11, it fails to compile.

<pre class="line-numbers"><code class="language-go">package main

import (
    "fmt"
    "time"
)

func init() {
	for {
		time.Sleep(time.Second)
		fmt.Println("hi")
	}
}

var main int
</code></pre>

<p>
</p>
</div>
-->

<a class="anchor" id="stack-overflow-is-unrecoverable"></a>
<h3>栈溢出不可被挽救，它将使程序崩溃。</h3>

<div>

在目前的主流Go编译器实现中，栈溢出是致命错误。一旦栈溢出发生，程序将不可恢复地崩溃。

<pre class="line-numbers"><code class="language-go">package main

func f() {
	f()
}

func main() {
	defer func() {
		recover() // 无法防止程序崩溃
	}()
	f()
}
</code></pre>

运行结果：

<pre class="output"><code>runtime: goroutine stack exceeds 1000000000-byte limit
fatal error: stack overflow

runtime stack:
...
</code></pre>

<p>
</p>

<p>
关于更多不可恢复的致命错误，请参考<a href="https://github.com/go101/go101/wiki/Panic-and-crash-cases">此篇维基文章</a>。
</p>
</div>

<a class="anchor" id="some-evaluation-order-are-compiler-dependent"></a>
<h3>某些表达式的估值顺序取决于具体编译器实现。</h3>

<p>
关于细节，请阅读<a href="evaluation-orders.html">表达式估值顺序规则</a>一文。
</p>

<a class="anchor" id="reflect-deep-equal"></a>
<h3><code>reflect.DeepEqual(x, y)</code>和<code>x == y</code>的结果可能会不同。</h3>


<div>
<p>
如果表达式<code>x</code>和<code>y</code>的类型不相同，则函数调用<code>DeepEqual(x, y)</code>的结果总为<code>false</code>，但<code>x == y</code>的估值结果有可能为<code>true</code>。
</p>

<p>
如果<code>x</code>和<code>y</code>为（同类型的）两个引用着不同其它值的指针值，则<code>x == y</code>的估值结果总为<code>false</code>，但函数调用<code>DeepEqual(x, y)</code>的结果可能为<code>true</code>，因为函数<code>reflect.DeepEqual</code>将比较<code>x</code>和<code>y</code>所引用的两个值。
</p>

<p>
第三个区别是当<code>x</code>和<code>y</code>处于一个循环引用链中时，<code>DeepEqual</code>调用的结果可能未必正确。
</p>

<p>
第四个区别是一个<code>DeepEqual(x, y)</code>调用无论如何不应该产生一个恐慌，但是如果<code>x</code>和<code>y</code>是两个动态类型相同的接口值并且它们的动态类型是不可比较类型的时候，<code>x == y</code>将产生一个恐慌。
</p>

一个展示了这些不同的例子：

<pre class="line-numbers"><code class="language-go">package main

import (
	"fmt"
	"reflect"
)

func main() {
	type Book struct {page int}
	x := struct {page int}{123}
	y := Book{123}
	fmt.Println(reflect.DeepEqual(x, y)) // false
	fmt.Println(x == y)                  // true

	z := Book{123}
	fmt.Println(reflect.DeepEqual(&z, &y)) // true
	fmt.Println(&z == &y)                  // false

	type T struct{p *T}
	t := &T{&T{nil}}
	t.p.p = t // form a cyclic reference chain.
	fmt.Println(reflect.DeepEqual(t, t.p)) // true
	fmt.Println(t == t.p)                  // false

	var f1, f2 func() = nil, func(){}
	fmt.Println(reflect.DeepEqual(f1, f1)) // true
	fmt.Println(reflect.DeepEqual(f2, f2)) // false

	var a, b interface{} = []int{1, 2}, []int{1, 2}
	fmt.Println(reflect.DeepEqual(a, b)) // true
	fmt.Println(a == b)                  // panic
}
</code></pre>

<p>
</p>

注意：如果传递给一个<code>DeepEqual</code>调用的两个实参均为函数类型值，则此调用只有在这两个实参都为nil并且它们的类型相同的情况下才返回<code>true</code>。
比较元素中含有函数值的容器值或者比较字段中含有函数值的结构体值也是类似的。
另外要注意：如果两个同类型切片共享相同的元素序列（即它们的长度相同并且它们的各对相应元素的地址也相同），则使用<code>DeepEqual</code>比较它们时返回的结果总是为<code>true</code>，即使它们的元素中含有函数值。
一个例子：

<pre class="line-numbers"><code class="language-go">package main

import (
	"fmt"
	"reflect"
)

func main() {
	a := [1]func(){func(){}}
	b := a
	fmt.Println(reflect.DeepEqual(a, a))       // false
	fmt.Println(reflect.DeepEqual(a[:], a[:])) // true
	fmt.Println(reflect.DeepEqual(a[:], b[:])) // false
	a[0] = nil
	fmt.Println(reflect.DeepEqual(a, a)) // true
}
</code></pre>

<p>
</p>

</div>

<a class="anchor" id="reflect-value-bytes"></a>
<h3><code>reflect.Value.Bytes()</code>方法返回一个<code>[]byte</code>值，它的元素类型<code>byte</code>可能并非属主参数代表的Go切片值的元素类型。</h3>

<div>
<p>
假设一个自定义类型<code>MyByte</code>的底层类型为内置类型<code>byte</code>，我们知道Go类型系统禁止切片类型<code>[]MyByte</code>的值转换为类型<code>[]byte</code>。
但是，当前的<code>reflect.Value</code>类型的<code>Bytes</code>方法的实现可以帮我们绕过这个限制。
此实现应该是违反了Go类型系统的规则。
</p>

例子：

<pre class="line-numbers"><code class="language-go">package main

import "bytes"
import "fmt"
import "reflect"

type MyByte byte

func main() {
	var mybs = []MyByte{'a', 'b', 'c'}
	var bs []byte

	// bs = []byte(mybs) // this line fails to compile

	v := reflect.ValueOf(mybs)
	bs = v.Bytes() // okay. Violating Go type system.
	fmt.Println(bytes.HasPrefix(bs, []byte{'a', 'b'})) // true

	bs[1], bs[2] = 'r', 't'
	fmt.Printf("%s \n", mybs) // art
}
</code></pre>

<p>
虽然这违反了Go类型系统的规则，但是貌似此违反并没有什么害处，相反，它带来了一些好处。
比如，我们可以将<code>bytes</code>标准库包中提供的函数（间接）应用到<code>[]MyByte</code>值上，如上例所示。
</p>

<p>
注意：<code>reflect.Value.Bytes()</code>方法<a href="https://github.com/golang/go/issues/27727">以后可能会被移除</a>。
</p>

</div>

<a class="anchor" id="check-file-existent"></a>
<h3>我们应该使用<code>os.IsNotExist(err)</code>而不是<code>err == os.ErrNotExist</code>来检查文件是否存在。</h3>

<div>

使用<code>err == os.ErrNotExist</code>可能漏掉一些错误。

<pre class="line-numbers"><code class="language-go">package main

import (
	"fmt"
	"os"
)

func main() {
	_, err := os.Stat("a-nonexistent-file.abcxyz")
	fmt.Println(os.IsNotExist(err))    // true
	fmt.Println(err == os.ErrNotExist) // false
}
</code></pre>

<p>
</p>

如果你的项目只支持Go 1.13+，则<a href="https://github.com/golang/go/issues/38198">更推荐</a>使用<code>errors.Is(err, os.ErrNotExist)</code>来检查文件是否存在。

<pre class="line-numbers"><code class="language-go">package main

import (
	"errors"
	"fmt"
	"os"
)

func main() {
	_, err := os.Stat("a-nonexistent-file.abcxyz")
	fmt.Println(errors.Is(err, os.ErrNotExist)) // true
}
</code></pre>

<p>
</p>

</div>



<a class="anchor" id="boolean-flag"></a>
<h3><code>flag</code>标准库包对待布尔命令选项不同于数值和字符串选项。</h3>

<div>
传递程序选项有三种形式。
<ol>
<li>
	<code>-flag</code>：仅适用于布尔选项。
</li>
<li>
	<code>-flag=x</code>：用于任何类型的选项。.
</li>
<li>
	<code>-flag x</code>：仅用于非布尔选项。
</li>
</ol>

<p>
请注意，使用第一种形式的布尔选项将被视为最后一个选项，其后面的所有项都被视为参数。
</p>

<pre class="line-numbers"><code class="language-go">package main

import "fmt"
import "flag"

var b = flag.Bool("b", true, "一个布尔选项")
var i = flag.Int("i", 123, "一个整数选项")
var s = flag.String("s", "hi", "一个字符串选项")

func main() {
	flag.Parse()
	fmt.Print("b=", *b, ", i=", *i, ", s=", *s, "\n")
	fmt.Println("arguments:", flag.Args())
}
</code></pre>

<p>
</p>

如果我们用下面显示的标志和参数运行下面的程序

<pre class="output"><code>./exampleProgram -b false -i 789 -s bye arg0 arg1
</code></pre>

输出结果会是：

<pre class="output"><code>b=true, i=123, s=hi
arguments: [false -i 789 -s bye arg0 arg1]
</code></pre>

<p>
这个输出显然不是我们所期望的。
</p>

我们应该像这样传递选项和参数：

<pre class="output"><code>./exampleProgram -b=false -i 789 -s bye arg0 arg1
</code></pre>

或者

<pre class="output"><code>./exampleProgram -i 789 -s bye -b arg0 arg1
</code></pre>

以获取我们期望的输出：

<pre class="output"><code>b=true, i=789, s=bye
arguments: [arg0 arg1]
</code></pre>

</div>

<a class="anchor" id="printf-positional-arguments"></a>
<h3><code>[Sp|Fp|P]rintf</code>函数支持位置参数。</h3>

<div>
下面的程序会打印<code>coco</code>。

<pre class="line-numbers"><code class="language-go">package main

import "fmt"

func main() {
	// The next line prints: coco
	fmt.Printf("%[2]v%[1]v%[2]v%[1]v", "o", "c")
}
</code></pre>

<p>
</p>
</div>




</div> <!-- summaries-items -->

<!--
<a class="anchor" id="remove-spaces-in-template"></a>
<h3>Since Go 1.6, we can .</h3>

https://golang.org/doc/go1.6 : {{a -}} sss {{- b}}



The exported fields and methods of embedded non-exported fields
are still exported for the embedding struct type.


json:"name: empty" // doesn't work

syscall package docs show current O arch defaultly
  https://golang.org/pkg/syscall/?GOOS=linux&GOARCH=mips64le

two non-defined struct types embedding two alias types which denote the same type are two different types.

non-exported field can't be set by reflection, but can be listed. Can read?

reflection created embedding type will not obtain meethods. still?

don't use == to compare two reflect.Value values, compare v1.Interface() and v2.Interface() instead (move to reflection article and tips)

don't use == compare two time.Time values, use time.EqualTo instead (move to tips)

https://golang.org/pkg/reflect/#pkg-note-BUG

https://golang.org/pkg/reflect/#Value.String
Print functions not always print the result of the String() method of a value.



size_t in go is int instead of uint, ..., good design. (to faq)

an untyped rune or int constant can be bound with a value which is larger than the max <code>rune</code> or <code>int</code> value in memory.

-128/-1 = -128


greedy goroutine https://github.com/golang/go/issues/10958
* It look some goroutines never get yielded, this make some other goroutines never get chances to run, why?
http://stackoverflow.com/questions/13107958/what-exactly-does-runtime-gosched-do

internal package

"go doc xyz" may show the docs of the first package named with "xyz"
https://github.com/golang/go/issues/24462


runtime.Caller/ Callers: depth onconsistencys

https://github.com/golang/go/issues/13890

https://github.com/golang/go/issues/24693

https://github.com/golang/go/issues/24721

https://github.com/golang/go/issues/20135

Try not to use multi-value assignments.
Reason 1: maybe bug. Reason 3: unspecified behaviours. 2: maybe inefficient.
https://github.com/golang/go/issues/23188#issuecomment-361482955
https://github.com/golang/go/issues/23017
https://github.com/golang/go/issues/22881
https://github.com/golang/go/issues/24448

https://github.com/golang/go/issues/24746

https://github.com/golang/go/issues/26463 maps do not shrink

Values of <code>expvar.Int</code> and <code>expvar.Float</code> need to be 64-bit aligned.

func main() {
	var a, b = 1.0, 0.0
	x, y := a/b, 0.0
	println(x, y) // +Inf +0.000000e+000
	println(x * y) // NaN
}

io/ioutil since Go 1.11

    The TempFile function now supports specifying where the random characters in the filename are placed.
    If the prefix argument includes a "*", the random string replaces the "*".
    For example, a prefix argument of "myname.*.bat" will result in a random filename such as "myname.123456.bat".
    If no "*" is included the old behavior is retained, and the random digits are appended to the end.

go links 101
   https://stackoverflow.com/questions/7044944/jquery-javascript-to-detect-os-without-a-plugin
   https://golang.org/pkg/syscall/ list all OS/arch pages

//godo/doc/builder
var windowsOnlyPackages = map[string]bool{
	"internal/syscall/windows":                     true,
	"internal/syscall/windows/registry":            true,
	"golang.org/x/exp/shiny/driver/internal/win32": true,
	"golang.org/x/exp/shiny/driver/windriver":      true,
	"golang.org/x/sys/windows":                     true,
	"golang.org/x/sys/windows/registry":            true,
}

go term(inoledgie)s 101

go contests 101 / summaries / snippets

go games

go practices
	* wasm + box2d: jslib: {drawRect, drawCircle, ...}
	* crawler
	* go.*
	* channel: chat
	* game
	  * https://github.com/faiface/pixel/wiki/Drawing-shapes-with-IMDraw
	* gui
	* web dev
	* db
	* ML, AI
	  * https://mb-14.github.io/tech/2018/10/24/gomarkov.html
	* net
	  * https://old.reddit.com/r/golang/comments/9r4sb3/using_go_for_networking/
	*

go101 tools
	* golf
	* mac
	* doc
	* json beautify
	* detect bad 64-bit alignement expectations: https://github.com/golang/go/issues/11891#issuecomment-433623786
	* find default import name is not constent with the last token in import path
	* check depreciated go env vars
	* find useless loops: https://github.com/golang/go/issues/28313





-->








